#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cJSON.h"

#include "item_manager.h"
#include "message_queue.h"
#include "cicd_config.h"
#include "cicd_common.h"

extern char global_owner[50];
extern char global_access_token[35];

typedef enum {
    BRANCH_EXIST_AND_NO_CHANGE, // 存在且未变化
    BRANCH_EXIST_AND_CHANGE,    // 存在且变化
    BRANCH_NOT_EXIST,           // 不存在
}branch_status;

// 分支节点
typedef struct _branch {
    char branch_name[128];   // branch name ━┓
    char hash[128];          // branch hash ━┻━━主键
    branch_status status;   // 状态
    struct _branch *next;   // 下一个分支节点
}branch_handler;

typedef struct {
    char branch_name[128];
    char hash[128];
}json_to_branch;

// 仓库节点
typedef struct _repo {
    char repo_name[128];     // 仓库名称(主键)
    branch_handler *branch_head;   // 带头结点
    struct _repo *next;     // 下一个仓库节点
}repo_handler;

/**
 * @brief 创建一个分支节点 
 */
static branch_handler *create_brach(const char *branch_name, const char *hash) {
    branch_handler *handler = (branch_handler *)malloc(sizeof(branch_handler));
    memset(handler, 0, sizeof(branch_handler));
    if(branch_name != NULL) {
        strncpy(handler->branch_name, branch_name, sizeof(handler->branch_name));
    }
    if(hash != NULL) {
        strncpy(handler->hash, hash, sizeof(handler->hash));
    }
    handler->status = BRANCH_EXIST_AND_NO_CHANGE;
    handler->next = NULL;
    return handler;
}

/**
 * @brief 通过仓库名寻找到仓库节点并返回
 */
static repo_handler *get_repo_node_by_repo_name(repo_handler *head, const char *reponame) {
    if(head->next == NULL) {
        return NULL;
    }
    repo_handler *repo_head = head->next;
    while(repo_head != NULL) {
        if(strcmp(repo_head->repo_name, reponame) == 0) {
            return repo_head;
        }
        repo_head = repo_head->next;
    }
    return NULL;
}

/**
 * @brief 在某一个仓库中，通过分支名进行查找
 */
static branch_handler *get_branch_by_branch_name(repo_handler *repo, const char *branchname) {
    branch_handler *head = repo->branch_head->next;
    while(head != NULL) {
        if(strcmp(head->branch_name, branchname) == 0) {
            return head;
        }
        head = head->next;
    }
    return NULL;
}

// 实现一个全打印接口，用于调试
void debug_show_all(repo_handler *handler) {
    repo_handler *head = handler->next;
    branch_handler *branch = NULL;
    while(head != NULL) {
        printf("repo name: %s\n", head->repo_name);
        branch = head->branch_head->next;
        while(branch != NULL) {
            printf("\tbranch name:%s\n\tbranch hash:%s\n\tbranch status:%d\n\n", branch->branch_name, branch->hash, branch->status);
            branch = branch->next;
        }
        head = head->next;
    }
}

// 初始化仓库句柄（仓库带头结点，分支带头结点）
void repo_init(repo_handler **handler) {
    (*handler) = (repo_handler *)malloc(sizeof(repo_handler));
    memset(*handler, 0, sizeof(repo_handler));
    (*handler)->branch_head = (branch_handler *)malloc(sizeof(branch_handler));
    memset((*handler)->branch_head, 0, sizeof(branch_handler));
    (*handler)->branch_head->next = NULL;
    (*handler)->next = NULL;
    strcpy((*handler)->repo_name, "head node");
}

// 根据仓库名和json串更新分支节点
void repo_update_by_json(repo_handler *handler, const char *repo, cJSON *json) {
    repo_handler *head = NULL;  // 头节点
    repo_handler *target_repo = NULL;   // 如果已经存在仓库则用该变量记录
    repo_handler *insert = NULL;    // 当该仓库不存在时，用于插入的节点

    json_to_branch arr[100] = { 0 };
    int total_branch_number = 0;
    int arr_counter = 0;
    int i;
    char *tmp = NULL;

    cJSON *branch = NULL;
    cJSON *value = NULL;

    branch_handler *branch_node = NULL;
    branch_handler *branch_temp = NULL;

    printf_debug("into repo_update_by_json\n");

    // 找到目标仓库
    head = handler;
    while(head->next != NULL) {
        if(strcmp(head->next->repo_name, repo) == 0) {
            target_repo = head->next;
            break;
        }
        head = head->next;
    }
    printf_debug("while finish\n");

    if(target_repo == NULL) {   // 没有目标仓库的情况下则创建新的仓库
        insert = (repo_handler *)malloc(sizeof(repo_handler));
        insert->next = NULL;
        strncpy(insert->repo_name, repo, sizeof(insert->repo_name));
        insert->branch_head = create_brach(NULL, NULL);
        insert->next = head->next;
        head->next = insert;
        target_repo = insert;   // 指向新插入的节点
        printf_debug("target repo created new one\n");
    }

    // 将json中的内容放到arr当中方便操作
    total_branch_number = cJSON_GetArraySize(json);
    printf_debug("total_branch_number is %d\n", total_branch_number);
    for(i = 0; i < total_branch_number; i++) {
        printf_debug("start for %d\n", i);
        branch = cJSON_GetArrayItem(json, i);
        value = cJSON_GetObjectItem(branch, "name");
        tmp = cJSON_Print(value);
        strncpy(arr[i].branch_name, tmp, sizeof(arr[i].branch_name));
        free(tmp);

        branch = cJSON_GetArrayItem(branch, 1);
        value = cJSON_GetObjectItem(branch, "sha");
        tmp = cJSON_Print(value);
        strncpy(arr[i].hash, tmp, sizeof(arr[i].hash));
        free(tmp);
        printf_debug("for %d ok\n", i);
    }
    arr_counter = total_branch_number;

    // 将所有节点状态设置为不存在
    branch_node = target_repo->branch_head->next;
    while(branch_node != NULL) {
        printf_debug("while\n");
        branch_node->status = BRANCH_NOT_EXIST;
        branch_node = branch_node->next;
    }
    printf_debug("while ok\n");

    // 按照arr寻找链表中的分支节点
    for(i = 0; i < total_branch_number; i++) {
        printf_debug("while\n");
        branch_node = get_branch_by_branch_name(target_repo, arr[i].branch_name);
        if(branch_node == NULL) {   // 如果没找到，那证明是新添加的节点，采用头插法，状态设置为存在且变化
            printf_debug("start if\n");
            branch_temp = (branch_handler *)malloc(sizeof(branch_handler));
            branch_temp->next = target_repo->branch_head->next;
            target_repo->branch_head->next = branch_temp;
            branch_temp->status = BRANCH_EXIST_AND_CHANGE;

            strncpy(branch_temp->branch_name, arr[i].branch_name, sizeof(branch_temp->branch_name));
            strncpy(branch_temp->hash, arr[i].hash, sizeof(branch_temp->hash));
            printf_debug("if ok\n");
        }
        else {  // 如果找到了
            printf_debug("start else\n");
            if(strcmp(arr[i].hash, branch_node->hash) != 0) {   // 判断一下哈希是否改变，如果改变则将状态设置为存在并改变
                printf_debug("hash changed\n");
                strncpy(branch_node->hash, arr[i].hash, sizeof(branch_node->hash)); // 重新拷贝哈希值，以防止下次寻找的时候数据错误
                branch_node->status = BRANCH_EXIST_AND_CHANGE;
            }
            else {  // 哈希没变就是分支没变化，不需要重新编译
                printf_debug("hash didn't change\n");
                branch_node->status = BRANCH_EXIST_AND_NO_CHANGE;
            }
            printf_debug("else ok\n");
        }
    }
    printf_success("Successfully obtained all branch information in the %s\n", repo);
}

// 使用仓库数据更新消息队列
void repo_update_mq(repo_handler *handler) {
    repo_handler *head_repo = handler->next;
    branch_handler *head_branch = NULL;
    branch_handler *temp = NULL;
    printf_debug("start repo_update_mq\n");
    while(head_repo != NULL) {
        head_branch = head_repo->branch_head;   // 存在删除分支节点的可能，需要先前一步
        while(head_branch != NULL && head_branch->next != NULL) {
            if(head_branch->next->status == BRANCH_NOT_EXIST) { // 如果是不存在则需要删除节点
                temp = head_branch->next;
                head_branch->next = temp->next;
                free(temp);
                continue;
            }
            else if(head_branch->next->status == BRANCH_EXIST_AND_CHANGE) {  // 如果状态发生变化则需要向消息队列中发送数据
                queue_compile_add(global_access_token, global_owner, head_repo->repo_name, head_branch->next->branch_name, head_branch->next->hash);
                head_branch->next->status = BRANCH_EXIST_AND_NO_CHANGE;
            }
            head_branch = head_branch->next;
        }
        head_repo = head_repo->next;
    }
    printf_success("Update message queue succeeded\n");
}

// 释放仓库句柄
void repo_free(repo_handler **handler) {
    repo_handler *repo_head = (*handler);
    repo_handler *repo_free = NULL;
    branch_handler *branch_head = NULL;
    branch_handler *branch_free = NULL;
    while(repo_head != NULL) {
        repo_free = repo_head;
        branch_head = repo_free->branch_head;
        while(branch_head != NULL) {
            branch_free = branch_head;
            branch_head = branch_head->next;
            free(branch_free);
        }
        repo_head = repo_head->next;
        free(repo_free);
    }
    *handler = NULL;
}
